/*
 * ad9833.c
 *
 * Copyright 2022 dh33ex <dh33ex@riseup.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA or see <http://www.gnu.org/licenses/>.
 *
 *
 */


#ifndef __msp430_h_
    #include <msp430.h>
#endif
#include "ad9833.h"

#define B28     0x2000
#define HLB     0x1000
#define FSELECT 0x0800
#define PSELECT 0x0400
#define RESET   0x0100
#define SLEEP1  0x0080
#define SLEEP12 0x0040
#define OPBITEN 0x0020
#define DIV2    0x0008
#define MODE    0x0002

#define FREQ0   0x4000
#define FREQ1   0x8000
#define PHASE0  0xC000
#define PHASE1  0xE000


unsigned short _current_waveform;


void AD9833_send(unsigned char ss, unsigned short word) {
    while(UCB0STAT & UCBUSY);   /* wait until SPI free */
    P2OUT &= ~ss;               /* clear SS */
    UCB0TXBUF = word >> 8;      /* send MSB */
    while (!(IFG2 & UCB0TXIFG));/* wait until TX ready */
    UCB0TXBUF = word;           /* send LSB */
    while (UCB0STAT & UCBUSY);  /* wait until SPI free */
    __delay_cycles(3);          /* wait a little */
    P2OUT |= ss;                /* set SS */
}


void AD9833_set_freq(unsigned char ss, unsigned long freq) {
    unsigned long raw_freq = (unsigned long)(freq * 10.7374);
    AD9833_send(ss, B28 | _current_waveform);               /* write full word */
    AD9833_send(ss, FREQ0 | (raw_freq & 0b11111111111111)); /* Freq0 LSB */
    AD9833_send(ss, FREQ0 | (raw_freq >> 14));              /* Freq0 MSB */
}


void AD9833_set_phase(unsigned char ss, float phase) {
    unsigned short raw_phase = (unsigned short)(phase * 652.2292);
    AD9833_send(ss, PHASE0 | raw_phase);                    /* write phase0 register */
}


void AD9833_init(unsigned char ss) {
    /* setup SPI */
    UCB0CTL1 |= UCSWRST;        /* put B0 into SW Reset */
    UCB0CTL1 |= UCSSEL_2;       /* choose SMCLK */
    UCB0BR0 = 1;                /* SMCLK=1M/1=1MHz */
    UCB0BR1 = 0;

    UCB0CTL0 |= UCSYNC          /* put B0 into SPI mode */
             | UCMSB            /* set MSB-first */
             | UCCKPH           /* set falling edge */
             | UCCKPL           /* set inactive state=HIGH */
             | UCMST;           /* set master mode */

    /* configure the ports */
    P1SEL |= BIT5;              /* P1.5 use CLK (11) */
    P1SEL2 |= BIT5;

    P1SEL |= BIT7;              /* P1.7 use SIMO (11) */
    P1SEL2 |= BIT7;

    P2SEL &= ~ss;               /* use primary function of ss */
    P2SEL2 &= ~ss;

    P2DIR |= ss;                /* setup SS */
    P2OUT |= ss;

    UCB0CTL1 &= ~UCSWRST;

    /* setup AD9833 */
    AD9833_send(ss, B28 | RESET);   /* reset + db28 */
    AD9833_set_freq(ss, 400);       /* Freq = 10C7 (400 Hz) */
    AD9833_set_phase(ss, 0);        /* Phase = 0 */
    AD9833_send(ss, B28);           /* clear reset */
}


void AD9833_set_waveform(unsigned char ss, unsigned short waveform) {
    _current_waveform = waveform;
    AD9833_send(ss, waveform);        /* send waveform code */
}
